package se.webbzon.boltzmann.item;

import se.webbzon.boltzmann.battle.battleaction.BattleActionFactory;
import se.webbzon.boltzmann.game.environment.GameEnvironment;
import se.webbzon.boltzmann.game.object.player.AbstractPlayerCharacter;
import se.webbzon.boltzmann.resource.Resources;
import se.webbzon.oschi01.resourceset.ResourceSet;
import se.webbzon.oschi01.textureset.Texture3D;

public abstract class AbstractItem implements Cloneable {
	
	// Item properties
	public static final int KEY_ITEM	= (1<<0);
	public static final int BATTLE_ITEM	= (1<<1);
	public static final int GAME_ITEM 	= (1<<2);
	
	// The properties of this item
	private final int properties;
	
	// The name of the item
	private final String name, description;
	
	// The base value of the item
	private final int baseValue;
	
	// The texture of this item
	private final ResourceSet<Texture3D> textureSet;
	
	/*============================================================
	Constructors
	============================================================*/
	
	/** Creates a new abstract item. **/
	public AbstractItem(
				int itemProperties,
				String name, 
				String description,
				int baseValue,
				String textureSetName) {
		this(itemProperties,name,description,baseValue,Resources.getTextureSet(textureSetName));
	}
	
	/** Creates a new abstract item. **/
	public AbstractItem(
				int itemProperties,
				String name, 
				String description,
				int baseValue,
				ResourceSet<Texture3D> textureSet) {
		this.properties = itemProperties;
		this.name = name;
		this.description = description;
		this.baseValue = baseValue;
		this.textureSet = textureSet;
	}
	
	/** Creates a new copy of the given abstract item. **/
	public AbstractItem(AbstractItem item) {
		this.properties = item.properties;
		this.name = item.name;
		this.description = item.description;
		this.baseValue = item.baseValue;
		this.textureSet = item.textureSet;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	/** Returns the name of this item. **/
	public String getName() {
		return name;
	}
	
	/** Returns the description of this item. **/
	public String getDescription() {
		return description;
	}
	
	/** Returns the base value of this item. **/
	public int getBaseValue() {
		return baseValue;
	}
	
	/** Returns true if this item is a key item. **/
	public boolean isKeyItem() {
		return isSet(properties,KEY_ITEM);
	}
	
	/** Returns true if this item is a battle item. **/
	public boolean isBattleItem() {
		return isSet(properties,BATTLE_ITEM);
	}
	
	/** Returns true if this item is a game item. **/
	public boolean isGameItem() {
		return isSet(properties,GAME_ITEM);
	}
	
	/** Returns the texture set associated with this item. **/
	public ResourceSet<Texture3D> getTextureSet() {
		return textureSet;
	}
	
	/** Returns the battle action factory of this abstract item. This
	 * method should be overridden if isBattleItem() returns true, 
	 * otherwise this method is guaranteed not to be called. **/
	public BattleActionFactory getBattleActionFactory() {
		return null;
	}
	
	/** Uses this abstract item in the provided game environment by the
	 * given player. This method should be overridden if isGameItem returns
	 * true, otherwise this method is guaranteed not to be called. **/
	public void useItem(GameEnvironment genv, AbstractPlayerCharacter player) {};
	
	@Override public abstract AbstractItem clone();
	
	@Override public boolean equals(Object obj) {
		if (obj instanceof AbstractItem) {
			AbstractItem other = (AbstractItem) obj;
			if (other.getTextureSet().equals(getTextureSet())) {
				return other.getName().equals(getName());
			} else
				return false;
		} else
			return false;
	}
	
	@Override public int hashCode() {
		return getName().hashCode();
	}
	
	/*============================================================
	Private Methods
	============================================================*/

	/** Returns true if the given property is set in the given properties. **/
	private static final boolean isSet(int properties, int property) {
		return ((properties & property) == property);
	}

}
